home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_055 / vt100 / kermit.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  22KB  |  865 lines

  1. /*************************************************************
  2.  * vt100 terminal emulator - KERMIT protocol support
  3.  *
  4.  *    v2.6 870227 DBW - bug fixes for all the stuff in v2.5
  5.  *    v2.5 870214 DBW - more additions (see readme file)
  6.  *    v2.4 861214 DBW - lots of fixes/additions (see readme file)
  7.  *    v2.3 861101 DBW - minor bug fixes
  8.  *    v2.2 861012 DBW - more of the same
  9.  *    v2.1 860915 DBW - new features (see README)
  10.  *         860901 ACS - Added eight bit quoting
  11.  *           860830 Steve Drew Wild card support, err recovry,bugs.
  12.  *         860823 DBW - Integrated and rewrote lots of code
  13.  *           860811 Steve Drew multi filexfer, bugs, status line ect..
  14.  *    v2.0 860809 DBW - Major rewrite
  15.  *    v1.1 860720 DBW    - Switches, 80 cols, colors, bug fixes
  16.  *    v1.0 860712 DBW    - First version released
  17.  *
  18.  *************************************************************/
  19.  
  20. #include "vt100.h"
  21.  
  22. #define MAXPACKSIZ 94       /* Maximum msgpkt size */
  23. #define CR         13       /* ASCII Carriage Return */
  24. #define LF         10       /* ASCII line feed */
  25. #define SP         32       /* ASCII space */
  26. #define DEL       127       /* Delete (rubout) */
  27.  
  28. #define MAXTRY    5        /* Times to retry a msgpkt */
  29. #define MYQUOTE  '#'       /* Quote character I will use */
  30. #define MYRPTQ   '~'       /* Repeat quote character */
  31. #define MYEBQ     '&'       /* 8th bit prefix character */
  32. #define MYPAD      0       /* Number of padding charss I will need */
  33. #define MYPCHAR    0       /* Padding character I need (NULL) */
  34. #define MYEOL    '\n'      /* End-Of-Line character I need */
  35.  
  36. #define tochar(ch)  ((ch) + ' ')
  37. #define unchar(ch)  ((ch) - ' ')
  38. #define ctl(ch)     ((ch) ^ 64 )
  39.  
  40. /* Global Variables */
  41.  
  42. int
  43.    size,      /* Size of present data */
  44.    osize,     /* Size of last data entry */
  45.    rpsiz,     /* Maximum receive msgpkt size */
  46.    spsiz,     /* Maximum send msgpkt size */
  47.    timint,    /* Time interval to wait */
  48.    pad,       /* How much padding to send */
  49.    n,         /* Packet number */
  50.    tp,        /* total packets */
  51.    numtry,    /* Times this msgpkt retried */
  52.    retry,     /* total retries */
  53.    oldtry,    /* Times previous msgpkt retried */
  54.    sendabort, /* flag for aborting send file  */
  55.    rptflg,    /* are we doing repeat quoting */
  56.    ebqflg,    /* are we doing 8th bit quoting */
  57.    notfirst,  /* is this the first file received */
  58.    first,     /* is this the first time in a file */
  59.    rpt,       /* current repeat count */
  60.    next,      /* what is the next character */
  61.    t;         /* current character */
  62. long
  63.    totbytes;  /* total bytes xfered on this file */
  64.  
  65. char 
  66.    state,     /* Present state of the automaton */
  67.    padchar,   /* Padding character to send */
  68.    eol,       /* End-Of-Line character to send */
  69.    quote,     /* Quote character in incoming data */
  70.    rptq,      /* Quote character for repeats */
  71.    ebq,          /* Quote character for 8th bit quoting */
  72.    ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */
  73.    msgpkt[MAXPACKSIZ+20], /* Message Packet buffer */
  74.    filnam[40],            /* remote file name */
  75.    snum[10],
  76.    sl1[] = "FILE            PKT NUM RETR BYTES",
  77.    sl2[] = "%-15s  %c %4d  %2d %6ld %5s",
  78.    sl3[50],
  79.    mainmode[10];
  80.  
  81. FILE *fp;     /* file for send/receive */
  82.  
  83. char *
  84. getfname(name)   /* returns ptr to start of file name from spec */
  85. char *name;
  86.     {
  87.     int l;
  88.  
  89.     l = strlen(name);
  90.     while(l && name[l] != '/' && name[l] != ':') l--;
  91.     if (name[l] == '/' || name[l] == ':') l++;
  92.     return(name += l);
  93.     }
  94.     
  95. doksend(file,more)
  96. char *file;
  97. int more;
  98.    {
  99.    int amount, c, wild;
  100.    char *p, **list = NULL;
  101.  
  102.    if (!strcmp(file,"$")) { saybye(); return(2); }
  103.    p = file;
  104.    while(*p && *p != '*' && *p != '?') p++;
  105.    if (*p) { 
  106.        wild = TRUE;
  107.        list = expand(file, &amount);
  108.        if (list == NULL)  req("KERMIT","No wild card match",0);
  109.        }
  110.    else {
  111.        wild = FALSE;
  112.        amount = 1;
  113.        }
  114.    for (c = 0; c < amount; c++) {
  115.        if (wild == TRUE) p = list[c];
  116.          else  p = file;
  117.        strcpy(filnam,getfname(p));
  118.        ttime = TTIME_KERMIT;
  119.        tp = retry = n = numtry = 0; totbytes = 0L;
  120.        if ((fp = fopen(p,"r")) == NULL) {
  121.            req("KERMIT: can't open send file:",p,0);
  122.            continue;
  123.            }
  124.        strcpy(mainmode,"SEND");
  125.        ClearBuffer();
  126.        if (sendsw()) dostats(' ',"DONE");
  127.        fclose(fp);
  128.        } 
  129.    free_expand(list);
  130.    return TRUE;
  131.    }
  132.  
  133. dokreceive(file,more)
  134. char *file;
  135. int more;
  136.    {
  137.    int retval;
  138.    
  139.    ttime = TTIME_KERMIT;
  140.    if (!strcmp(file,"$")) { saybye(); return(2); }
  141.    strcpy(filnam, file);   
  142.    if (server) strcpy(mainmode,"GET");
  143.    else           strcpy(mainmode,"RECV");
  144.    tp =  retry = n =  numtry = notfirst = 0; totbytes = 0L;
  145.    ClearBuffer();
  146.    retval  = recsw();
  147.    return(retval);
  148.    }
  149.  
  150. sendsw()
  151.    {
  152.    char sinit(), sfile(), sdata(), seof(), sbreak();
  153.    sendabort = 0;
  154.    state = 'S';
  155.    while(TRUE) {
  156.       switch(state) {
  157.          case 'S':   state = sinit();  break;
  158.          case 'F':   state = sfile();  break;
  159.          case 'D':   state = sdata();  break;
  160.          case 'Z':   state = seof();   break;
  161.          case 'B':   state = sbreak(); break;
  162.          case 'C':   if (sendabort) return FALSE;
  163.                      else return TRUE;
  164.          case 'E':   dostats('E',"ERROR");  /* so print the err and abort */
  165.                      print_host_err(ackpkt);
  166.                      return(FALSE);
  167.          case 'A':   if (timeout == USERABORT) {
  168.              timeout = GOODREAD;
  169.                          n = (n+1)%64;             
  170.                           sendabort = 1;
  171.                           dostats('A',"ABORT");
  172.                           strcpy(msgpkt, "D");
  173.                           state = 'Z'; 
  174.                           break;
  175.                           }
  176.                      if (timeout == TIMEOUT)  dostats('A',"TMOUT");
  177.                      else { /* protocol error dectected by us */
  178.              dostats('A',"ERROR");
  179.              print_our_err();
  180.              }
  181.                      return(FALSE);
  182.          default:    return(FALSE);
  183.          }
  184.       }
  185.    }
  186.  
  187. char sinit()
  188.    {
  189.    int num, len;
  190.    
  191.    retry++;
  192.    if (numtry++ > MAXTRY) return('A');
  193.    spar(msgpkt);
  194.  
  195.    spack('S',n,9,msgpkt);
  196.    switch(rpack(&len,&num,ackpkt)) {
  197.       case 'N':  return(state);
  198.       case 'Y':  if (n != num) return(state);
  199.                  rpar(ackpkt);
  200.                  if (eol == 0) eol = '\n';
  201.                  if (quote == 0) quote = MYQUOTE;
  202.                  numtry = 0;
  203.                  retry--;
  204.                  n = (n+1)%64;
  205.                  return('F');
  206.       case 'E':  return('E');
  207.       case FALSE:if (timeout == USERABORT) state = 'A';
  208.                  return(state);
  209.       default:   return('A');
  210.       }
  211.     }
  212.  
  213. char sfile()
  214.    {
  215.    int num, len;
  216.  
  217.    retry++;
  218.    if (numtry++ > MAXTRY) return('A');
  219.  
  220.    spack('F',n,strlen(filnam),filnam);
  221.    switch(rpack(&len,&num,ackpkt)) {
  222.       case 'N':
  223.          num = (--num<0 ? 63:num);
  224.          if (n != num) return(state);
  225.       case 'Y':
  226.          if (n != num) return(state);
  227.          numtry = 0;
  228.          retry--;
  229.          n = (n+1)%64;
  230.          first = 1;
  231.          size = getpkt();
  232.          return('D');
  233.       case 'E':
  234.          return('E');
  235.       case FALSE: if (timeout == USERABORT) state = 'A';
  236.                   return(state);
  237.       default:
  238.          return('A');
  239.       }
  240.    }
  241.  
  242. char sdata()
  243.    {
  244.    int num, len;
  245.    
  246.    retry++;
  247.    if (numtry++ > MAXTRY) return('A');
  248.  
  249.    spack('D',n,size,msgpkt);
  250.    switch(rpack(&len,&num,ackpkt)) {
  251.       case 'N':
  252.          num = (--num<0 ? 63:num);
  253.          if (n != num) return(state);
  254.       case 'Y':
  255.          if (n != num) return(state);
  256.          numtry = 0;
  257.          retry--;
  258.          n = (n+1)%64;
  259.          if ((size = getpkt()) == 0) return('Z');
  260.          return('D');
  261.       case 'E':
  262.          return('E');
  263.       case FALSE: if (timeout == USERABORT) state = 'A';
  264.                   return(state);
  265.       default:    
  266.          return('A');
  267.       }
  268.    }
  269.  
  270. char seof()
  271.    {
  272.    int num, len;
  273.    retry++;
  274.    if (numtry++ > MAXTRY) return('A');
  275.  
  276. /*   if (timeout == USERABORT) {*/    /* tell host to discard file */
  277. /*      timeout = GOODREAD;    */
  278. /*        spack('Z',n,1,"D");    */
  279. /*        }            */
  280. /*   else            */
  281.     spack('Z',n,sendabort,msgpkt);
  282.    switch(rpack(&len,&num,ackpkt)) {
  283.       case 'N':
  284.          num = (--num<0 ? 63:num);
  285.          if (n != num) return(state);
  286.       case 'Y':
  287.          if (n != num) return(state);
  288.          numtry = 0;
  289.          retry--;
  290.          n = (n+1)%64;
  291.          return('B');
  292.       case 'E':
  293.          return('E');
  294.       case FALSE: return(state);
  295.       default:
  296.          return('A');
  297.       }
  298.    }
  299.  
  300. char sbreak()
  301.    {
  302.    int num, len;
  303.    retry++;
  304.    if (numtry++ > MAXTRY) return('A');
  305.  
  306.    spack('B',n,0,msgpkt);
  307.    switch (rpack(&len,&num,ackpkt)) {
  308.       case 'N':
  309.          num = (--num<0 ? 63:num);
  310.          if (n != num) return(state);
  311.       case 'Y':
  312.          if (n != num) return(state);
  313.          numtry = 0;
  314.      retry--;
  315.          n = (n+1)%64;
  316.          return('C');
  317.       case 'E':
  318.          return('E');
  319.       case FALSE: return(state);
  320.       default:    return ('A');
  321.       }
  322.    }
  323.  
  324. /* timeout equals USERABORT so lets end the file and quit  */
  325. /* when host receives 'Z' packet with "D" in data field he */
  326. /* should discard the file.                                */
  327. /*
  328. sabort()
  329.    {
  330.    dostats(' ',"ABORT");
  331.    n = (n+1)%64;
  332.    retry--;
  333.    state = 'Z';
  334.    while (state == 'Z') state = seof();
  335.    while (state == 'B') state = sbreak();
  336.    return(FALSE);
  337.    }
  338. */ 
  339.  
  340.  
  341. recsw()
  342.    {
  343.    char rinit(), rfile(), rdata();
  344.  
  345.    state = 'R';
  346.    
  347.    while(TRUE) {
  348.       switch(state) {
  349.          case 'R':   state = rinit(); break;
  350.          case 'Z':
  351.          case 'F':   state = rfile(); break;
  352.          case 'D':   state = rdata(); break;
  353.          case 'C':   return(TRUE);
  354.          case 'E':
  355.          case 'A':   /* easy way to cleanly abort
  356.             should really send and ACK
  357.             with "X" in data field and 
  358.             wait for host to abort but
  359.             not all kermits support
  360.             this feature.           */
  361.             if (timeout == USERABORT){
  362.             /* send an error packet back   */
  363.                          dostats('A',"ABORT");
  364.                          spack('E',n,12,"User aborted"); 
  365.                      }
  366.                      else if (timeout == TIMEOUT) {
  367.                 /* we timed out waiting */
  368.                     /* will we need to spack here ?*/
  369.              dostats('A',"TMOUT");
  370.              }
  371.                 /* must be 'E' from host or we
  372.                  detected a protocol error */
  373.                          else dostats('A',"ERROR");
  374.  
  375.              if (state == 'E') print_host_err(msgpkt);
  376.  
  377.              else if (timeout == GOODREAD) /* tell host why */
  378.             print_our_err();
  379.                /* will this kill all files ?*/
  380.                      do  {
  381.                          ttime = 2;        
  382.                          readchar();
  383.                          }  while (timeout == GOODREAD);
  384.                      fclose(fp);
  385.                      sendstring("\r");
  386.                      return(FALSE);
  387.      default:    return(FALSE);    
  388.          }
  389.       }
  390.    }
  391.  
  392.  
  393.  
  394. char rinit()
  395.    {
  396.    int len, num;
  397.    retry++;
  398.    if (numtry++ > MAXTRY) return('A');
  399.  
  400.    if (server) spack('R',n,strlen(filnam),filnam);
  401.    else  spack('N',n,0,0);
  402.    switch(rpack(&len,&num,msgpkt)) {
  403.       case 'S':
  404.          rpar(msgpkt);
  405.          spar(msgpkt);
  406.          spack('Y',n,9,msgpkt);
  407.          oldtry = numtry;
  408.          numtry = 0;
  409.          retry--;
  410.          n = (n+1)%64;
  411.          return('F');
  412.       case 'E':
  413.          return('E');
  414.       case FALSE:
  415.          if (timeout == USERABORT) return('A');
  416.          spack('N',n,0,0);
  417.          return(state);
  418.       default:
  419.          return('A');
  420.       }
  421.    }
  422.  
  423. char rfile()
  424.    {
  425.    int num, len;
  426.    retry++;
  427.    if (numtry++ > MAXTRY) return('A');
  428.  
  429.    switch(rpack(&len,&num,msgpkt)) {
  430.       case 'S':
  431.          if (oldtry++ > MAXTRY) return('A');
  432.          if (num == ((n==0) ? 63:n-1)) {
  433.             spar(msgpkt);
  434.             spack('Y',num,9,msgpkt);
  435.             numtry = 0;
  436.             return(state);
  437.             }
  438.          else return('A');
  439.       case 'Z':
  440.          if (oldtry++ > MAXTRY) return('A');
  441.          if (num == ((n==0) ? 63:n-1)) {
  442.             spack('Y',num,0,0);
  443.             numtry = 0;
  444.             return(state);
  445.             }
  446.          else return('A');
  447.       case 'F':
  448.          if (num != n) return('A');
  449.      strcpy(filnam,msgpkt);
  450.          if (p_convert) {
  451.              char *p;
  452.          p = &filnam[0];
  453.              while (*p) { *p = tolower(*p); p++; }
  454.              }
  455.      if (notfirst) { 
  456.              totbytes = 0L;
  457.              dostats('F',"RECV");
  458.              }
  459.      /* is the first file so emit actual file name from host */
  460.          else {
  461.          notfirst++;
  462.          }
  463.          if ((fp = fopen(filnam,"w")) == NULL) {
  464.          req("KERMIT: Unable to create file:",filnam,0);
  465.          strcpy(msgpkt,"VT100 - Kermit - cannot create file: ");
  466.          strcat(msgpkt,filnam);
  467.          spack('E',n,strlen(msgpkt),msgpkt); /* let host know */
  468.              dostats('E',"ERROR");
  469.              return ('\0');       /* abort everything */
  470.              }
  471.          spack('Y',n,0,0);
  472.          oldtry = numtry;
  473.          numtry = 0;
  474.          retry--;
  475.          n = (n+1)%64;
  476.          return('D');
  477.  
  478.       /* totaly done server sending no more */
  479.       case 'B':
  480.          if (num != n) return ('A');
  481.          spack('Y',n,0,0);
  482.          retry--;
  483.          return('C');
  484.       case 'E':
  485.          return('E');
  486.       case FALSE:
  487.          if (timeout == USERABORT) return('A');
  488.          spack('N',n,0,0);
  489.          return(state);
  490.       default:
  491.          return ('A');
  492.       }
  493.    }
  494.  
  495. char rdata()
  496.    {
  497.    int num, len;
  498.    retry++;
  499.    if (numtry++ > MAXTRY) return('A');
  500.  
  501.    switch(rpack(&len,&num,msgpkt)) {
  502.       case 'D':
  503.          if (num != n) {
  504.             if (oldtry++ > MAXTRY) return('A');
  505.             if (num == ((n==0) ? 63:n-1)) {
  506.                spack('Y',num,6,msgpkt); 
  507.                numtry = 0;
  508.                return(state);
  509.                }
  510.             else return('A');
  511.             }
  512.          decode();
  513.          spack('Y',n,0,0);
  514.          oldtry = numtry;
  515.          numtry = 0;
  516.          retry--;
  517.          n = (n+1)%64;
  518.          return('D');
  519.       case 'Z':
  520.          if (num != n) return('A');
  521.          spack('Y',n,0,0);
  522.          n = (n+1)%64;
  523.          retry--;
  524.          dostats('Z',"DONE");
  525.      fclose(fp);
  526.          return('Z');
  527.       case 'F':
  528.          if (oldtry++ > MAXTRY) return('A');
  529.          if (num == ((n==0) ? 63:n-1)) {
  530.          spack('Y',num,0,0);
  531.          numtry = 0;
  532.          return(state);
  533.              }
  534.       case 'E':
  535.          return('E');
  536.       case FALSE:
  537.          if (timeout == USERABORT) return('A');
  538.          spack('N',n,0,0);
  539.          return(state);
  540.       default:
  541.         return('A');
  542.       }
  543.    }
  544.  
  545.  
  546. spack(type,num,len,data)
  547. char type, *data;
  548. int num, len;
  549.    {
  550.    int i;
  551.    char chksum, buffer[100];
  552.    register char *bufp;
  553.    
  554.    dostats(type,mainmode);
  555.    bufp = buffer;
  556.    ClearBuffer();
  557.    for (i=1; i<=pad; i++) sendchar(padchar);
  558.  
  559.    *bufp++ = SOH;
  560.    *bufp++ = tochar(len+3);
  561.    chksum  = tochar(len+3);
  562.    *bufp++ = tochar(num);
  563.    chksum += tochar(num);
  564.    *bufp++ = type;
  565.    chksum += type;
  566.  
  567.    for (i=0; i<len; i++) {
  568.       *bufp++ = data[i];
  569.       chksum += data[i];
  570.       }
  571.    chksum = (((chksum&0300) >> 6)+chksum)&077;
  572.    *bufp++ = tochar(chksum);
  573.    *bufp++ = '\r';
  574.    *bufp++ = '\n';
  575.    *bufp   = 0;
  576.    sendstring(buffer);
  577.    }
  578.  
  579. rpack(len,num,data)
  580. int *len, *num;
  581. char *data;
  582.    {
  583.    int i, done;
  584.    char type, cchksum, rchksum;
  585.    char t = '\0';
  586.  
  587.     do {
  588.        t = readchar();
  589.        if (timeout != GOODREAD) return(FALSE);
  590.        } while (t != SOH);
  591.  
  592.     done = FALSE;
  593.     while (!done) {
  594.        t = readchar();
  595.        if (timeout != GOODREAD) return(FALSE);
  596.        if (t == SOH) continue;
  597.        cchksum = t;
  598.        *len = unchar(t)-3;
  599.        t = readchar();
  600.        if (timeout != GOODREAD) return(FALSE);
  601.        if (t == SOH) continue;
  602.        cchksum = cchksum + t;
  603.        *num = unchar(t);
  604.        t = readchar();
  605.        if (timeout != GOODREAD) return(FALSE);
  606.        if (t == SOH) continue;
  607.        cchksum = cchksum + t;
  608.        type = t;
  609.        for (i=0; i<*len; i++) {
  610.           t = readchar();
  611.           if (timeout != GOODREAD) return(FALSE);
  612.           if (t == SOH) continue;
  613.           cchksum = cchksum + t;
  614.           data[i] = t;
  615.           }
  616.        data[*len] = 0;
  617.        t = readchar();
  618.        if (timeout != GOODREAD) return(FALSE);
  619.        rchksum = unchar(t);
  620.        t = readchar();
  621.        if (timeout != GOODREAD) return(FALSE);
  622.        if (t == SOH) continue;
  623.        done = TRUE;
  624.        }
  625.    dostats(type,mainmode);
  626.    cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
  627.    if (cchksum != rchksum) return(FALSE);
  628.    return((int)type);
  629.    }
  630.  
  631. getpkt() {
  632.    int i,eof;
  633.  
  634.    static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
  635.                     '\0', '\0', '\0', '\0', '\0' };
  636.  
  637.    if (first == 1) {
  638.       first = 0;
  639.       *leftover = '\0';
  640.       t = getc(fp);
  641.       if (t == EOF) {
  642.          first = 1;
  643.          return(size = 0);
  644.          }
  645.       totbytes++;
  646.       }
  647.    else if (first == -1) {
  648.       first = 1;
  649.       return(size = 0);
  650.       }
  651.    for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
  652.    *leftover = '\0';
  653.    rpt = 0;
  654.    eof = 0;
  655.    while (!eof) {
  656.       next = getc(fp);
  657.       if (next == EOF) {
  658.          first = -1;
  659.          eof   =  1;
  660.          }
  661.       else totbytes++;
  662.       osize = size;
  663.       encode(t);
  664.       t = next;
  665.       if (size == spsiz-3) return(size);
  666.       if (size > spsiz-3) {
  667.          for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) ;
  668.          size = osize;
  669.          msgpkt[size] = '\0';
  670.          return(size);
  671.          }
  672.       }
  673.    return(size);
  674.    }
  675.  
  676. void encode(a)
  677. char a;
  678.    {
  679.    int a7,b8;
  680.  
  681.    if (p_mode == 1 && a == '\n') {
  682.       rpt = 0;
  683.       msgpkt[size++] = quote;
  684.       msgpkt[size++] = ctl('\r');
  685.       if (size <= spsiz-3) osize = size;
  686.       msgpkt[size++] = quote;
  687.       msgpkt[size++] = ctl('\n');
  688.       msgpkt[size]   = '\0';
  689.       return;
  690.       }
  691.    if (rptflg) {
  692.       if (a == next && (first == 0)) {
  693.          if (++rpt < 94) return;
  694.          else if (rpt == 94) {
  695.             msgpkt[size++] = rptq;
  696.             msgpkt[size++] = tochar(rpt);
  697.             rpt = 0;
  698.             }
  699.          }
  700.       else if (rpt == 1) {
  701.          rpt = 0;
  702.          encode(a);
  703.          if (size <= spsiz-3) osize = size; 
  704.          rpt = 0;
  705.          encode(a);
  706.          return;
  707.          }
  708.       else if (rpt > 1) {
  709.          msgpkt[size++] = rptq;
  710.          msgpkt[size++] = tochar(++rpt);
  711.          rpt = 0;
  712.          }
  713.       }
  714.    a7 = a & 0177;
  715.    b8 = a & 0200;
  716.  
  717.    if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  718.     msgpkt[size++] = ebq;
  719.     a = a7;
  720.     }
  721.    
  722.    if ((a7 < SP) || (a7==DEL)) {
  723.       msgpkt[size++] = quote;
  724.       a = ctl(a);
  725.       }
  726.    if (a7 == quote) msgpkt[size++] = quote;
  727.    if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
  728.  
  729.    if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  730.        msgpkt[size++] = quote;  /* if doing 8th-bit prefixes */
  731.  
  732.    msgpkt[size++] = a;
  733.    msgpkt[size] = '\0';
  734.    }
  735.  
  736. void decode()
  737.    {
  738.    USHORT  a, a7, b8;
  739.    char *buf;
  740.  
  741.    buf = msgpkt;
  742.    rpt = 0;
  743.    
  744.    while ((a = *buf++) != '\0') {
  745.       if (rptflg) {
  746.          if (a == rptq) {
  747.             rpt = unchar(*buf++);
  748.             a = *buf++;
  749.             }
  750.          }
  751.       b8 = 0;
  752.       if (ebqflg) {                  /* 8th-bit prefixing? */
  753.       if (a == ebq) {            /* Yes, got an 8th-bit prefix? */
  754.           b8 = 0200;             /* Yes, remember this, */
  755.           a = *buf++;            /* and get the prefixed character. */
  756.       }
  757.       }
  758.       if (a == quote) {
  759.          a  = *buf++;
  760.          a7 = a & 0177;
  761.          if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
  762.          }
  763.       a |= b8;
  764.       if (rpt == 0) rpt = 1;
  765.       if (p_mode == 1 && a == '\r') continue;
  766.       totbytes += rpt;
  767.       for (; rpt > 0; rpt--) putc(a, fp);
  768.       }
  769.    return;
  770.    }
  771.  
  772. void spar(data)
  773. char data[];
  774.    {
  775.    data[0] = tochar(MAXPACKSIZ);
  776.    data[1] = tochar(TTIME_KERMIT);
  777.    data[2] = tochar(MYPAD);
  778.    data[3] = ctl(MYPCHAR);
  779.    data[4] = tochar(MYEOL);
  780.    data[5] = MYQUOTE;
  781.    if ((p_parity > 0) || ebqflg) {         /* 8-bit quoting... */
  782.     data[6] = MYEBQ;          /* If parity or flag on, send &. */
  783.     if ((ebq > 0040 && ebq < 0100) || /* If flag off, then turn it on  */
  784.        (ebq > 0140 && ebq < 0177) || /* if other side has asked us to */
  785.        (ebq == 'Y')) ebqflg = 1;
  786.     }
  787.     else                    /* Normally, */
  788.        data[6] = 'Y';                /* just say we're willing. */
  789.     data[7] = '1';
  790.     data[8] = MYRPTQ;
  791.     data[9] = '\0';
  792.     }
  793.  
  794. void rpar(data)
  795. char data[];
  796.     {
  797.     spsiz   = unchar(data[0]);
  798.     ttime   = unchar(data[1]);
  799.     pad     = unchar(data[2]);
  800.     padchar = ctl(data[3]);
  801.     eol     = unchar(data[4]);
  802.     quote   = data[5];
  803.     rptflg  = 0;
  804.     ebqflg  = 0;
  805.     if (data[6] == 0) return;
  806.     ebq = data[6];
  807.     if ((ebq > 040 && ebq < 0100) || 
  808.     (ebq > 0140 && ebq < 0177)) ebqflg = 1;
  809.     else if (((p_parity > 0) || ebqflg) && (ebq == 'Y')) {
  810.     ebqflg = 1;
  811.     ebq = '&';
  812.     }
  813.     else ebqflg = 0;
  814.     if (data[7] == 0) return;
  815.     if (data[8] == 0) return;
  816.     rptq    = data[8];
  817.     rptflg  = ((rptq > 040 && rptq < 0100) || 
  818.     (rptq > 0140 && rptq < 0177));
  819.     }
  820.  
  821. saybye()
  822.   {
  823.   int len,num;
  824.   spack('G',n,1,"F");  /* shut down server no more files */
  825.   rpack(&len,&num,ackpkt);
  826.   }
  827.  
  828. print_our_err()
  829.     {
  830.     if (retry > MAXTRY || oldtry > MAXTRY) {
  831.     req("KERMIT:","Too may retries for packet",0);
  832.     strcpy(msgpkt,"VT100 KERMIT: Too many retries for packet");
  833.     }
  834.     else {
  835.     req("KERMIT:","Protocol Error",0);
  836.     strcpy(msgpkt,"VT100 KERMIT: Protocol Error");
  837.     }
  838.     spack('E',n,strlen(msgpkt));
  839.     }
  840.  
  841. print_host_err(msg)
  842.   char *msg;
  843.   {
  844.   req("KERMIT Host Error:",msg,0);
  845.   }
  846.  
  847. dostats(type,stat)
  848. char type,*stat;
  849.     {
  850.     if (type == 'Y' || type == 'N' || type == 'G') return;
  851.     sprintf(sl3,sl2,filnam,type,n+(tp*64),retry-1,(long)totbytes,stat);
  852.     if (n==63) tp++;
  853.     req(sl1,sl3,0);
  854.     }
  855.  
  856. ClearBuffer()
  857.     {
  858.     AbortIO(Read_Request);
  859.     Read_Request->IOSer.io_Command = CMD_CLEAR;
  860.     DoIO(Read_Request);
  861.     Read_Request->IOSer.io_Command = CMD_READ;
  862.     SendIO(Read_Request);
  863.     }
  864.  
  865.